
using System;
using System.Data;
using System.ComponentModel;
using System.Globalization;
using System.Collections;

namespace PantheonSoftware.InfoCollection.Business
{
	//// <summary>
	//// Infobase represents an abstract base class for all item
	//// classes
	//// 
	//// The only prerequisite for this class is that the parent MUST
	//// implement <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IList.htm">IList</exref>
	//// 
	//// Used in conjunction with the accompanying collection base
	//// class, this is no problem as it implements <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref3/html/T_System_ComponentModel_IBindingList.htm">IBindingList</exref>.
	//// 
	//// It also implements:
	////   * <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_IComparable.htm">IComparable</exref>
	////     \- the CompareTo() method is abstract because it needs to
	////     access a typed parent. See documentation for a good derived
	////     implementation
	////   * IEditableObject: Uses the DataRow functionality
	////   * INotifyPropertyChanged: is properly implemented in the
	////     derived class. Use the codesith template for an example
	////   * IDisposable
	//// 
	//// See accompanying CodeSmith templates and articles for
	//// detailed information 
	//// </summary>                                                                                                                                                                   
	[CLSCompliant(true)]	
	public abstract class InfoBase : IComparable, IEditableObject, INotifyPropertyChanged, IDisposable
	{
		private	DataRow		_dr;

        /// <summary>
        /// PropertyChanged event is fired whenever a property is modified.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

		#region Constructors
		/// <summary>
		/// Implements a the InfoBase object.
		/// </summary>
		public InfoBase(object col, DataRow dr)
		{
            _parent = col as IList;
            if (_parent == null) throw new InvalidCastException("The Parent collection MUST at least implement IList");

			_dr = dr;
		}
		#endregion	
		
		#region Relationships
		private object _parent;
		//// <summary>
		//// \Returns the parent collection object. 
		//// </summary>                             
		public virtual object Parent
		{
			get
			{
				return _parent;
			}
		}

        //// <summary>
        //// Implementation of the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IList.htm">IList</exref>
        //// \version of the Parent object. Used internally and unlikely
        //// to be called or used by anyone else.
        //// 
        //// Use the <see cref="PantheonSoftware.InfoCollection.Business.InfoBase.Parent" text="Parent" />
        //// property instead. 
        //// </summary>                                                                                                                            
        public IList ListParent
        {
            get
            {
                return (IList)this.Parent; // Already tested for IList in the constructor
            }
        }
		#endregion	

		#region Object Methods

        //// <summary>
        //// Called by individual properties in order to correctly
        //// implement INotifyPropertyChanged
        //// </summary>
        //// <param name="propertyName">The property which has just
        ////                            changed</param>            
        protected void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
	
		/// <summary>
		/// Delete this object and removes it from the collection. Call
		/// <see cref='CustomersInfoCollection.Update'/> to delete it from the database.
		/// </summary>
		public void Delete()
		{
			ListParent.Remove(this);
		}

		/// <summary>
		/// Called from the parents Remove() or RemoveAt(). 
        /// Do not call directly. 
		/// </summary>
		public void InternalDelete()
		{
			_dr.Delete();
		}

		/// <summary>
		/// Discard any changes made to the object.
		/// </summary>
		public void Undo()
		{
			_dr.RejectChanges();
		}
		#endregion	

		#region IEditableObject Methods

		/// <summary>
		/// Begins an edit operation on the internal DataRow object.
		/// </summary>
	    public void BeginEdit()
		{
	        _dr.BeginEdit();
	    }
	
		/// <summary>
		/// Cancels the current edit on the internal DataRow object.
		/// </summary>
	    public void CancelEdit()
		{
            if (_dr.RowState == DataRowState.Added)
	            ListParent.Remove(this);
	        _dr.CancelEdit();
	    }
	
		/// <summary>
		/// Ends the edit occurring on the row.
		/// </summary>
	    public void EndEdit()
		{
	        _dr.EndEdit();
	    }
		#endregion

		#region IComparable Members

		/// <summary>
		/// This method implements the IComparable interface. 
		/// The method implements CompareTo for any string / value property.
		/// </summary>
		/// <param name="obj">An object to compare with this instance. </param>
		/// <returns>Value that is zero if this instance is equal to obj, less than zero if this instance 
		/// is less than obj and greater than zero This instance is greater than obj.
		/// </returns>
		int IComparable.CompareTo(object obj)
		{
			if (Object.Equals(obj, null))
				return 1;
			InfoBase ci = obj as InfoBase;
			if (ci == null)
				return 1;
			return this.CompareTo(ci);
		}

		/// <summary>
		/// This method implements the IComparable interface. 
		/// The method implements CompareTo for InfoBase objects.
		/// For more complicated compares,  
		/// </summary>
		/// <param name="obj">A InfoBase object to compare with this instance. </param>
		/// <returns>Value that is zero if this instance is equal to obj, less than zero if this instance 
		/// is less than obj and greater than zero This instance is greater than obj.</returns>
		public abstract int CompareTo(InfoBase obj);
        //{
        //    if (Object.Equals(obj, null))
        //        return 1;
        //    //return this.Id - obj.Id;
        //    //TODO: Replace dbo.CustomersColumns.MyDefaultCompareProperty with a valid value

        //    //if (this.Parent.SortBy == null) this.Parent.SortBy = UtilityClass.PropertyFromFieldName(typeof(InfoBase), CustomersColumns.CompanyName.ToString());
        //    //PropertyDescriptor pd = this.Parent.SortBy;
        //    //return string.Compare(pd.GetValue(this).ToString(), pd.GetValue(obj).ToString() , true, System.Globalization.CultureInfo.CurrentCulture);
        //}

		/// <summary>
		/// The Equals method determines whether the specified System.Object is equal to this InfoBase object.
		/// </summary>
		/// <param name="obj">The Object object against which the current InfoBase object is compared.</param>
		/// <returns>Returns true if the specified System.Object is equal to the current InfoBase 
		/// object or false if it is not equal.</returns>
	    public override bool Equals(object obj)
		{
			if (obj == null)
				return false;

			if (this.GetType() != obj.GetType())
				return false;

			InfoBase ni = obj as InfoBase;
			return this.CompareTo(ni) == 0;
	    }

		/// <summary>
		/// The Equals method determines whether the specified InfoBase is equal to this InfoBase object.
		/// </summary>
		/// <param name="obj">A InfoBase object</param>
		/// <returns>Returns true if the specified System.Object is equal to the current InfoBase 
		/// object or false if it is not equal.</returns>
		/// <remarks>Omitting Equals violates FxCop rule: IComparableImplementationsOverrideEquals.</remarks>
	    public bool Equals(InfoBase obj)
		{
			if (object.Equals(obj, null))
				return false;
	        return this.CompareTo(obj) == 0;
	    }

		/// <summary>
		/// The GetHashCode method serves as a hash function for this InfoBase object. 
		/// This hash function is suitable for use in hashing algorithms and data structures like a 
		/// hash table.
		/// </summary>
		/// <returns>A hash value for the current InfoBase object.</returns>
	    public override int GetHashCode()
		{
	        // TODO: Implement the hash code
	        //Return Convert.ToInt32(Me.PrintId, CultureInfo.InvariantCulture)
	        return 0;
	    }
		
		// Omitting any of the following operator overloads
		// violates FxCop rule: IComparableImplementationsOverrideOperators.
		// Omitting any of the following operator overloads
		// violates FxCop rule: IComparableImplementationsOverrideOperators.
		/// <summary>
		/// Overloads the == operator
		/// </summary>
		/// <param name="obj1">The name of the first operand</param>
		/// <param name="obj2">The name of the second operand</param>
		/// <returns>True if the 2 objects are equal.</returns>
		public static bool operator == (InfoBase obj1, InfoBase obj2)
		{
			if (object.Equals(obj1, null))
			{
				return (object.Equals(obj2, null));
			}
			return obj1.Equals(obj2);
		}  

        /// <summary>
        /// Overloads the != operator
        /// </summary>
	    /// <param name="obj1">The name of the first operand</param>
		/// <param name="obj2">The name of the second operand</param>
        /// <returns>True if the 2 objects are different. </returns>
		public static bool operator != (InfoBase obj1, InfoBase obj2)
		{
			return !(obj1==obj2);
		}  
		/// <summary>
		/// Overloads the less than operator
		/// </summary>
		/// <param name="obj1">The name of the first operand</param>
		/// <param name="obj2">The name of the second operand</param>
		/// <returns>True if the first object is less than the second object.</returns>
		public static bool operator < (InfoBase obj1, InfoBase obj2)
		{
			return (obj1.CompareTo(obj2) < 0);
		}  
		//// <summary>
		//// Overloads the greater than operator
		//// </summary>
		//// <param name="obj1">The name of the first operand</param>
		//// <param name="obj2">The name of the second operand</param>
		//// <returns>
		//// True if the first object is greater than the second object. 
		//// </returns>                                                  
		public static bool operator > (InfoBase obj1, InfoBase obj2)
		{
			return (obj1.CompareTo(obj2) > 0);
		}  
		#endregion

		#region Properties for InfoBase
        //// <summary>
        //// \Internal <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref2/html/T_System_Collections_IList.htm">DataRow</exref>
        //// \object upon which this object is based on. 
        //// </summary>                                                                                                                  
        public DataRow Row
        {
            get
            {
                return _dr;
            }
            set
            {
                if (_dr != value)
                {
                    _dr = value;
                    NotifyPropertyChanged("Row");
                }
            }
        }

		//// <summary>
		//// Gets the current state of the row in regard to its
		//// relationship to the <exref target="ms-help://MS.VSCC.v80/MS.MSDN.vAug06.en/cpref4/html/T_System_Data_DataRowCollection.htm">DataRowCollection</exref>.
		//// </summary>
		//// <remarks>
		//// \Returns the value of the internal DataRow's RowState
		//// property 
		//// </remarks>                                                                                                                                            
		public DataRowState RowStatus
		{
			get
			{
				return _dr.RowState;
			}
		}
		
		/// <summary>
		/// Gets the custom error description for a row.
		/// </summary>
		public string RowError
		{
			get
			{
				return _dr.RowError;
			}
		}


        /// <summary>
        /// Gets a value indicating whether this instance has errors.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance has errors; otherwise, <c>false</c>.
        /// </value>
		public bool HasErrors
		{
			get
			{
				return _dr.HasErrors;
			}
		}

		#endregion	
		
		#region IDisposable
        

        ///@@ / <summary>
        //// Add a summary here...
        //// </summary>
        //// <value>
        //// Add a description here...
        //// </value>
        //// <returns>
        //// Add a return value description here...
        //// </returns>                            
        public void Dispose()
        {
            Dispose(true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SupressFinalize to
            // take this object off the finalization queue 
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

		bool disposed;
        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the 
        // runtime from inside the finalizer and you should not reference 
        // other objects. Only unmanaged resources can be disposed.
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if(disposing)
                {
	                
                }
             
                // Call the appropriate methods to clean up 
                // unmanaged resources here.
                // If disposing is false, 
                // only the following code is executed.
            }
            disposed = true;         
        }
		// Avoid destructors which slow down instantiation and are not necessarily garbage collected if 
		// no longer accessible. 
		#endregion


    }
}

